Rust 简介和特性
1. Rust 简介
Rust 是一种系统编程语言,由 Mozilla 开发,旨在提供内存安全、并发性和高性能。Rust 的设计哲学是“安全、并发、实用”,它通过所有权系统、借用检查和生命周期等机制来保证内存安全,同时提供了丰富的并发编程支持。
1.1 Rust 的主要特性
- 内存安全:Rust 通过所有权系统、借用检查和生命周期机制来防止常见的内存错误,如空指针引用、数据竞争等。
- 并发性:Rust 提供了强大的并发编程支持,包括线程、消息传递和共享状态等。
- 高性能:Rust 的编译器优化和零成本抽象使得生成的代码具有很高的性能。
- 现代语法:Rust 的语法设计现代且富有表现力,支持泛型、特质(Traits)、模式匹配等高级特性。
2. 环境搭建
在开始编写 Rust 程序之前,我们需要搭建 Rust 的开发环境。Rust 的安装和管理主要通过 rustup 工具进行,而项目的构建和管理则通过 cargo 工具完成。
2.1 安装 Rust
首先,我们需要安装 rustup,这是 Rust 的安装和管理工具。可以通过以下命令在终端中安装:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
安装完成后,可以通过以下命令验证安装是否成功:
rustc --version
cargo --version
2.2 使用 Cargo
cargo 是 Rust 的包管理器和构建工具。它可以帮助我们创建项目、管理依赖、构建和运行代码。
2.2.1 创建新项目
使用 cargo 创建一个新的 Rust 项目:
cargo new hello_world
cd hello_world
这会创建一个名为 hello_world 的新项目,包含一个基本的项目结构:
hello_world/
├── Cargo.toml
└── src
└── main.rs
Cargo.toml:项目的配置文件,包含项目的元数据和依赖。src/main.rs:项目的入口文件,包含main函数。
2.2.2 构建和运行项目
在项目目录下,可以使用以下命令构建和运行项目:
cargo build
cargo run
cargo build 会编译项目,生成可执行文件;cargo run 则会编译并运行项目。
3. 创建第一个 Rust 程序
让我们在 src/main.rs 文件中编写第一个 Rust 程序,输出 "Hello, Rust!"。
fn main() {
println!("Hello, Rust!");
}
保存文件后,使用 cargo run 运行程序,你将看到输出:
Hello, Rust!
4. 变量和数据类型
Rust 是一种静态类型语言,这意味着所有变量在编译时都必须具有明确的类型。Rust 支持多种基本数据类型,包括整数、浮点数、布尔值和字符。
4.1 变量声明
在 Rust 中,变量默认是不可变的(immutable)。要声明一个变量,使用 let 关键字:
let x = 5;
如果你想让变量可变,可以使用 mut 关键字:
let mut y = 10;
y = 20;
4.2 数据类型
Rust 支持多种基本数据类型:
- 整数类型:
i8,i16,i32,i64,i128,u8,u16,u32,u64,u128 - 浮点数类型:
f32,f64 - 布尔类型:
bool - 字符类型:
char
例如:
let a: i32 = 42;
let b: f64 = 3.14;
let c: bool = true;
let d: char = 'R';
5. 控制流
Rust 提供了多种控制流语句,包括 if、loop、while 和 for。
5.1 if 语句
if 语句用于条件判断:
let number = 5;
if number < 10 {
println!("The number is less than 10");
} else {
println!("The number is greater than or equal to 10");
}
5.2 loop 循环
loop 用于无限循环,直到使用 break 语句退出:
let mut count = 0;
loop {
count += 1;
if count == 5 {
break;
}
println!("Count: {}", count);
}
5.3 while 循环
while 循环在条件为真时执行:
let mut count = 0;
while count < 5 {
count += 1;
println!("Count: {}", count);
}
5.4 for 循环
for 循环用于遍历集合:
let numbers = [1, 2, 3, 4, 5];
for number in numbers.iter() {
println!("Number: {}", number);
}
6. 所有权系统
Rust 的核心特性之一是所有权系统,它通过所有权、借用和生命周期机制来保证内存安全。
6.1 所有权
在 Rust 中,每个值都有一个所有者(owner),并且同一时间只能有一个所有者。当所有者超出作用域时,值会被自动释放。
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 的所有权被转移给 s2
// println!("{}", s1); // 这行代码会导致编译错误,因为 s1 的所有权已经被转移
println!("{}", s2);
}
6.2 借用
借用(borrowing)允许我们在不转移所有权的情况下访问值。借用分为不可变借用和可变借用。
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // 不可变借用
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
7. 借用和引用
引用(reference)是借用的一种形式,允许我们在不转移所有权的情况下访问值。引用分为不可变引用和可变引用。
7.1 不可变引用
不可变引用允许我们读取值,但不能修改它:
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
7.2 可变引用
可变引用允许我们修改值,但同一时间只能有一个可变引用:
fn main() {
let mut s1 = String::from("hello");
change(&mut s1);
println!("{}", s1);
}
fn change(s: &mut String) {
s.push_str(", world");
}
8. 生命周期
生命周期(lifetime)是 Rust 中用于确保引用有效的机制。生命周期注解用于显式指定引用的有效范围。
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
}
println!("The longest string is {}", result);
}
9. 结构体和枚举
9.1 结构体
结构体(struct)是自定义数据类型,允许我们将多个相关的值组合在一起。
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("[email protected]"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
println!("User: {} <{}>", user1.username, user1.email);
}
9.2 枚举
枚举(enum)允许我们定义一个类型,该类型的值可以是多个可能的变体之一。
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::Write(String::from("hello"));
match msg {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move to ({}, {})", x, y),
Message::Write(text) => println!("Write: {}", text),
Message::ChangeColor(r, g, b) => println!("Change color to ({}, {}, {})", r, g, b),
}
}
10. 模式匹配
模式匹配(pattern matching)是 Rust 中一种强大的控制流工具,允许我们根据值的结构进行匹配。
fn main() {
let number = 7;
match number {
1 => println!("One"),
2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
13..=19 => println!("A teen"),
_ => println!("Ain't special"),
}
}
11. 模块系统
Rust 的模块系统允许我们将代码组织成模块(module),并通过路径(path)来访问模块中的项。
11.1 定义模块
在 src/lib.rs 或 src/main.rs 中定义模块:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {
println!("Added to waitlist");
}
}
}
fn main() {
front_of_house::hosting::add_to_waitlist();
}
11.2 使用 use 关键字
use 关键字用于将模块中的项引入当前作用域:
use front_of_house::hosting;
fn main() {
hosting::add_to_waitlist();
}
12. Cargo 包管理器
Cargo 是 Rust 的包管理器和构建工具,用于管理项目的依赖、构建和发布。
12.1 添加依赖
在 Cargo.toml 文件中添加依赖:
[dependencies]
rand = "0.8"
然后在代码中使用依赖:
use rand::Rng;
fn main() {
let secret_number = rand::thread_rng().gen_range(1..101);
println!("Secret number: {}", secret_number);
}
12.2 发布 crate
使用 cargo publish 命令可以将你的 crate 发布到 crates.io,供其他人使用。
13. 创建和发布 crate
13.1 创建 crate
使用 cargo new 命令创建一个新的 crate:
cargo new my_crate --lib
13.2 发布 crate
在发布之前,确保你的 crate 已经准备好,并且 Cargo.toml 文件中包含所有必要的信息。然后使用以下命令发布:
cargo publish
14. 使用外部依赖
在 Cargo.toml 文件中添加外部依赖,并在代码中使用:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 1, y: 2 };
let serialized = serde_json::to_string(&point).unwrap();
println!("serialized = {}", serialized);
}
15. 泛型
泛型(generics)允许我们编写适用于多种类型的代码。
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let numbers = vec![34, 50, 25, 100, 65];
let result = largest(&numbers);
println!("The largest number is {}", result);
}
16. 特质(Traits)
特质(traits)类似于其他语言中的接口,定义了类型必须实现的方法。
trait Summary {
fn summarize(&self) -> String;
}
struct NewsArticle {
headline: String,
location: String,
author: String,
content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
fn main() {
let article = NewsArticle {
headline: String::from("Penguins win the Stanley Cup Championship!"),
location: String::from("Pittsburgh, PA, USA"),
author: String::from("Iceburgh"),
content: String::from("The Pittsburgh Penguins once again are the best hockey team in the NHL."),
};
println!("New article available! {}", article.summarize());
}
17. 错误处理
Rust 提供了多种错误处理机制,包括 Result 和 Option。
17.1 Result 类型
Result 类型用于处理可能失败的计算:
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("Cannot divide by zero"))
} else {
Ok(a / b)
}
}
fn main() {
let result = divide(10, 2);
match result {
Ok(value) => println!("Result: {}", value),
Err(e) => println!("Error: {}", e),
}
}
17.2 Option 类型
Option 类型用于处理可能不存在的值:
fn find_even(numbers: &[i32]) -> Option<i32> {
for &number in numbers {
if number % 2 == 0 {
return Some(number);
}
}
None
}
fn main() {
let numbers = [1, 3, 5, 7, 8, 9];
match find_even(&numbers) {
Some(even) => println!("Found an even number: {}", even),
None => println!("No even numbers found"),
}
}
18. 智能指针
智能指针(smart pointers)是 Rust 中一种特殊的类型,它们拥有指向数据的指针,并提供额外的功能,如